/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bimager.jtwain;


import com.mortennobel.imagescaling.AdvancedResizeOp;
import com.mortennobel.imagescaling.ProgressListener;
import com.mortennobel.imagescaling.ResampleOp;
import com.sun.media.jai.widget.DisplayJAI;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.media.jai.InterpolationNearest;
import javax.media.jai.InterpolationTable;
import javax.media.jai.JAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.RasterFactory;
import javax.media.jai.TiledImage;
import javax.swing.Scrollable;
import javax.swing.SwingConstants;

/**
 *
 * @author Amskape
 */
public class ImageCanvas extends DisplayJAI implements Scrollable{

      Rectangle currentRect = null;
      Rectangle rectToDraw = null;
      Rectangle previousRectDrawn = new Rectangle();
      private BasicStroke bs;

   /**
    *  A gradient paint is used to create a distinctive-looking selection
    *  rectangle outline.
    */

   private GradientPaint gp;
      
       /**
    *  Mouse coordinates when mouse button pressed.
    */

   private int srcx, srcy;

   /**
    *  Latest mouse coordinates during drag operation.
    */

   private int destx, desty;

   /**
    *  Location and extents of selection rectangle.
    */

   private Rectangle rectSelection;
      
      
     protected PlanarImage image;
     protected AffineTransform atx = new AffineTransform();
     protected int imagewidth, imageheight,nbands;
     protected int[] imageData;
     protected int[] pixels;
     String imageFileName;
     File imageFile;
     BufferedImage canvasimage;
    public ImageCanvas() {
        addMouseMotionListener(this);
        addMouseListener(this);
    }

    public ImageCanvas(RenderedImage image) {
        super(image);
        addMouseMotionListener(this);
        addMouseListener(this);
      
    }

    public String getImageFileName() {
        return imageFileName;
    }

    public File getImageFile() {
        return imageFile;
    }

    public void setImageFileName(String imageFileName) {
        this.imageFileName = imageFileName;
    }

    public void setImageFile(File imageFile) {
        this.imageFile = imageFile;
    }
    
     
     
      public ImageCanvas(PlanarImage img,String filename,File file){
          
          rectSelection = new Rectangle ();

        // Define the stroke for drawing selection rectangle outline.

        bs = new BasicStroke (1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
                              0, new float [] { 1, 0 }, 0);

        // Define the gradient paint for coloring selection rectangle outline.

        gp = new GradientPaint (0.0f, 0.0f, Color.blue, 0.0f, 0.0f, Color.white,
                                true);
          
          
          
          
          
         addMouseMotionListener(this);
         addMouseListener(this);
         image       = img;
         imagewidth  = img.getWidth();
         imageheight = img.getHeight();
         imageFileName   = filename;
         imageFile =file;
         SampleModel sm = img.getSampleModel();
         nbands = sm.getNumBands();
         Raster inputRaster = img.getData();
         pixels = new int[nbands*imagewidth*imageheight];
         inputRaster.getPixels(0,0,imagewidth,imageheight,pixels);
         loadImage();
         
        setAutoscrolls(true);
         
         
         
         
         
      }
      public void loadImage()
      {
        
          if(nbands == 3)        
          canvasimage = new BufferedImage(imagewidth, imageheight, BufferedImage.TYPE_INT_RGB);
          else 
            canvasimage = new BufferedImage(imagewidth, imageheight, BufferedImage.TYPE_BYTE_GRAY);  
          WritableRaster raster = canvasimage.getRaster();
          raster.setPixels(0,0,imagewidth,imageheight,pixels);
          canvasimage.setData(raster);
          refresh();
      }
   
     public  Dimension getViewerSize(double imageAspectRatio){
        Dimension d= Toolkit.getDefaultToolkit().getScreenSize();
        int maxWidth = (int)(d.width *3/4.0);
        int maxHeight = (int)(d.height*3/4.0);
        double screenAspectRatio = maxWidth/(double)maxHeight;
        int viewerWidth,viewerHeight;
        if(imageAspectRatio  > screenAspectRatio){
            viewerWidth =   maxWidth;
            viewerHeight = (int)( maxHeight* screenAspectRatio/imageAspectRatio);
        }else{
            viewerHeight =   maxHeight;
            viewerWidth = (int)(maxWidth* imageAspectRatio/screenAspectRatio);
        }
        return new Dimension(viewerWidth, viewerHeight);
   }
      public void paintComponent(Graphics gc){
           Dimension d = new Dimension(imagewidth, imageheight); //getViewerSize(imagewidth/(double)imageheight);
           setPreferredSize(new Dimension(d.width, d.height));
           Graphics2D g = (Graphics2D)gc;
          /* Rectangle rect = this.getBounds();
         
         if((imagewidth != rect.width) || (imageheight != rect.height)){
             double magx = rect.width/(double)imagewidth ;
             double magy = rect.height/(double)imageheight ;
             atx.setToScale(magx, magy);
         }*/
      g.drawImage(canvasimage, null, 0, 0);
       if (srcx != destx || srcy != desty)
      {
          // Compute upper-left and lower-right coordinates for selection
          // rectangle corners.

          int x1 = (srcx < destx) ? srcx : destx;
          int y1 = (srcy < desty) ? srcy : desty;

          int x2 = (srcx > destx) ? srcx : destx;
          int y2 = (srcy > desty) ? srcy : desty;

          // Establish selection rectangle origin.

          rectSelection.x = x1;
          rectSelection.y = y1;

          // Establish selection rectangle extents.

          rectSelection.width = (x2-x1)+1;
          rectSelection.height = (y2-y1)+1;

          // Draw selection rectangle.

          Graphics2D g2d = (Graphics2D) g;
          g2d.setColor (new Color(0, 0, 255, 20));          
          g2d.fill (rectSelection);
          g2d.setStroke (bs);
          g2d.setPaint (gp);
          g2d.draw (rectSelection);
      }
       //g.drawRenderedImage(  image.createSnapshot(), atx);
      }

    public PlanarImage getImage() {
        return image;
    }
    public void getBufferedImage(int[] pixels)
    {
        
        
        
    }
    public int getImagewidth() {
        return imagewidth;
    }

    public int getImageheight() {
        return imageheight;
    }

    public void setImage(PlanarImage image) {
        this.image = image;
    }
      
      
      
      public boolean saveImage(String filename)
        {
            //PlanarImage image =  getImage();
           // JAI.create("filestore",image,filename,"TIFF");
           jtwain jt= new jtwain();
           
           jt.saveTiff("", imageFileName,imagewidth,imageheight, pixels,nbands,image.getColorModel().getPixelSize());
            
            
            
            return true;
        }
      
      
      
    
      
      
      
       public void rotateRight()
       {
       
           /*canvasimage = null;
            * repaint();*/
         removerefresh();
         int offsetdest,offset;
       //  BufferedImage im = new BufferedImage(imageheight, imagewidth, BufferedImage.TYPE_INT_RGB);
         imageData = new int[imagewidth*imageheight*nbands];
        //  WritableRaster outputRaster = im.getRaster();
         for(int w=0;w<imagewidth;w++)
        {
         for(int h=0;h<imageheight;h++)
         {
           offsetdest = ((imageheight-h-1)+(w*imageheight))*nbands;
           offset = ((imagewidth*h*nbands)+w*nbands);
       for(int band=0;band<nbands;band++){
            imageData[offsetdest+band] = (int) (pixels[offset+band]);
         }

        }
        }
      pixels = imageData;
    
      int temp   = imagewidth;
      imagewidth = imageheight;
      imageheight= temp;
      
      
      
      loadImage();
   
   }
        public void rotateLeft()
   {
      
        int offset;
         int j=0;
	removerefresh();
        imageData = new int[imagewidth*imageheight*nbands];
       // WritableRaster outputRaster = im.getRaster();
        for(int w=0;w<imagewidth;w++){
          for(int h=0;h<imageheight;h++){

                offset = ((h+1)*imagewidth-(w+1))*nbands ;
               for(int band=0;band<nbands;band++){

                           imageData[j+band] =    pixels[offset+band];
                           }
             j= j+nbands;
                           // imageData[j++] =    pixels[2width-1];
                          }

                  }
          
       
      pixels = imageData;
    
    //  outputRaster.setPixels(0,0,imageheight,imagewidth,pixels);
    
      //  im.setData(outputRaster);
      int temp   = imagewidth;
      imagewidth = imageheight;
      imageheight= temp;
       loadImage();
      /*   try {
       * ImageIO.write(im, "jpg", new File("E:\\Workspace\\Netbeans\\rr.jpg"));
       * //JAI.create("filestore",tiledImage,"rgbpattern.tif","TIFF");
       * 
       * 
       * //JAI.create("filestore",tiledImage,"rgbpattern.tif","TIFF");
       * 
       * // repaint();
       * } catch (IOException ex) {
       * Logger.getLogger(ImageCanvas.class.getName()).log(Level.SEVERE, null, ex);
       * }*/
       
       
   }
     public  void flipH()
    {
         
        int offsetdest,offset;
removerefresh();
        int[] imageData = new int[imagewidth*imageheight*nbands];
        for( int y = 0; y < imageheight; y++ ) {
                for( int x = 0; x < imagewidth; x++ ) {
                  offset = ((imagewidth-x-1)+y*imagewidth)*nbands;
                 offsetdest = (y*imagewidth+x)*nbands;
                   for(int band=0;band<nbands;band++){
                       imageData[offsetdest+band] = pixels[offset+band];
                        //outputRaster.setSample(x, y, band, inputRaster.getSample(, y, band));
                       
                       
                    
                      }
                    

		}
		}
         pixels = imageData;
        loadImage();
    }
   public  void flipV()
    {
        removerefresh();
           int offsetdest,offset;
         imageData = new int[imagewidth*imageheight*nbands];
      for( int y = 0; y < imageheight; y++ ) {
	   for( int x = 0; x < imagewidth; x++ ) {
               
                offset = ((imagewidth*(imageheight-y-1))+x)*nbands;
                 offsetdest = (y*imagewidth+x)*nbands;
		 for(int band=0;band<nbands;band++){
                       
                       // outputRaster.setSample(x, y, band, inputRaster.getSample(x, height-y-1, band));
                       imageData[offsetdest+band] = pixels[offset+band];  
                       
                    
                      }
                    

		}
		}
        
       pixels = imageData;
        loadImage();
    }
   public boolean crop()
   {
       
        
      if (srcx == destx && srcy == desty)
          return true;
         canvasimage = null;
          removerefresh();
      // There is nothing to crop if the selection rectangle is only a single
      // point.
     
     
    

      // Assume success.

     

      // Compute upper-left and lower-right coordinates for selection rectangle
      // corners.

      int x1 = (srcx < destx) ? srcx : destx;
      int y1 = (srcy < desty) ? srcy : desty;

      int x2 = (srcx > destx) ? srcx : destx;
      int y2 = (srcy > desty) ? srcy : desty;

      // Compute width and height of selection rectangle.
     
      int width = (x2-x1)+1;
      int height = (y2-y1)+1;
         Raster inputRaster = image.getData();
        WritableRaster outputRaster = inputRaster.createCompatibleWritableRaster(0,0 , imagewidth, imageheight);//inputRaster.createCompatibleWritableRaster();
        outputRaster.setPixels(0, 0,imagewidth , imageheight, pixels);
        
        
        
        
        
       // SampleModel sampleModel = image.getSampleModel(); //RasterFactory.createPixelInterleavedSampleModel( DataBuffer.TYPE_INT,height,width,nbands);
       // ColorModel colorModel =  image.getColorModel();
       // Point orgin = new Point(x1, y1);
        //outputRaster.setPixels(x2, y2, width, height, dArray);
        // WritableRaster outputRaster;
         // outputRaster = new WritableRaster();
        
        
        
        
        
     // WritableRaster raster = RasterFactory.
      imageData = new int[width*height*nbands]; 
      outputRaster.getPixels(x1, y1, width, height, imageData);
       destx = srcx = 0;
       desty = srcy = 0;
      pixels = imageData;
       
      imagewidth = width;
      imageheight= height;
      loadImage();
     

        return true;
   }
   public void removerefresh()
   {
       removeAll();
       revalidate();
       repaint();
       
   }
     public void refresh()
   {
     
       revalidate();
       repaint();
       
   }
   // public int[] resizePixels(int[] pixels,int w1,int h1,int w2,int h2) {
   public void scale(int width,int height)
   {
        
       
        ResampleOp  resampleOp = new ResampleOp (width,height);
        resampleOp.setUnsharpenMask(AdvancedResizeOp.UnsharpenMask.Normal);
        resampleOp.addProgressListener(new ProgressListener() {
        public void notifyProgress(float fraction) {
         System.out.printf("Still working - %f percent %n",fraction*100);
          } 
        });
        BufferedImage scaled = resampleOp.filter(canvasimage, null);
        canvasimage = null;
        removerefresh();
         // repaint();
       imageData = new int[width*height*nbands]; 
       WritableRaster raster = scaled.getRaster();
       raster.getPixels(0, 0, width, height, imageData);
       pixels = imageData;
       imagewidth = width;
       imageheight= height;
       loadImage();
      
   }
    @Override
    public void mousePressed(MouseEvent e) {
        super.mousePressed(e); //To change body of generated methods, choose Tools | Templates.
        if (canvasimage == null)
                      return;

                  destx = srcx = e.getX ();
                  desty = srcy = e.getY ();

                  repaint ();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        super.mouseReleased(e); //To change body of generated methods, choose Tools | Templates.
     //updateSize(e);
    
        
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        super.mouseDragged(e); //To change body of generated methods, choose Tools | Templates.
  if (image == null)
                       return;

                   destx = e.getX ();
                   desty = e.getY ();
          Rectangle r = new Rectangle(e.getX(), e.getY(), 1, 1);
          scrollRectToVisible(r);
        
                   repaint (); 
    }
     @Override
      public Dimension getPreferredSize() {
      
         Dimension d = new Dimension(imagewidth, imageheight); //getViewerSize(imagewidth/(double)imageheight);
          setPreferredSize(new Dimension(d.width, d.height));
            return super.getPreferredSize();
       
    }
    @Override
      public Dimension getPreferredScrollableViewportSize() {
      return getPreferredSize();
      }
      
      @Override
      public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {
       //Get the current position.
        int currentPosition = 0;
        if (orientation == SwingConstants.HORIZONTAL) {
            currentPosition = visibleRect.x;
        } else {
            currentPosition = visibleRect.y;
        }

        //Return the number of pixels between currentPosition
        //and the nearest tick mark in the indicated direction.
        if (direction < 0) {
            int newPosition = currentPosition -
                             (currentPosition / maxUnitIncrement)
                              * maxUnitIncrement;
            return (newPosition == 0) ? maxUnitIncrement : newPosition;
        } else {
            return ((currentPosition / maxUnitIncrement) + 1)
                   * maxUnitIncrement
                   - currentPosition;
        }
      }
      
      @Override
      public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {
        if (orientation == SwingConstants.HORIZONTAL) {
            return visibleRect.width - maxUnitIncrement;
        } else {
            return visibleRect.height - maxUnitIncrement;
        }
      }
     
     @Override
      public boolean getScrollableTracksViewportWidth() {
      return false;
      }
      
      @Override
      public boolean getScrollableTracksViewportHeight() {
      return false;
      }
      private int maxUnitIncrement = 1;
      public void setMaxUnitIncrement(int pixels) {
        maxUnitIncrement = pixels;
    }
    
}
